﻿#ifndef ASYNCBASE_H
#define ASYNCBASE_H

#include <memory>
#include <functional>
#include <thread>
#include <future>
#include <condition_variable>
#include <iostream>


class ThreadHelper {
public:

    // THRFUN如果需要退出返回非0值
    using THRFUN = std::function<int()>;

    ThreadHelper(THRFUN sfun, bool once = false) : quitFlag(once), thread_function(std::move(sfun))
    {
        // 这里要注意下，对于线程来说sfun是个临时变量，所以需要保存到thread_function。
        thr_handle = std::thread([&](){ do{  if(thread_function() != 0){quitFlag = true;break;}}while(!quitFlag);});
        //thr_handle = std::thread([&](){ do{  quitFlag = thread_function();}while(!quitFlag);});
    }

    ~ThreadHelper(){
        thrstop();
    }

    bool isRunning(){return !quitFlag;}

    void thrstop() {
        if (quitFlag == false) {
            quitFlag = true;
            thr_handle.join();
        }
    }
private:
    std::atomic_bool quitFlag;
    std::thread thr_handle;
    std::function<int()> thread_function;
};

template <typename OBJ>
class notifyCond
{
private:
    OBJ   param;
    std::atomic_bool    flagNotify;
    std::mutex          mutex_notify;
    std::condition_variable cond_var;

public:
    notifyCond():flagNotify(false){}
    ~notifyCond(){}

    void conditionPub(OBJ& obj){
        std::unique_lock<std::mutex> ulock(mutex_notify);
        flagNotify.store(true);
        cond_var.notify_one();
    //    param.store(obj,std::memory_order_release);
        param = std::move(obj);
    }

    int conditionWait(std::chrono::milliseconds time,OBJ& _left){
        std::unique_lock<std::mutex> ulock(mutex_notify); 
        if(cond_var.wait_for(ulock,time,[&](){return flagNotify.load();})){
            _left = std::move(param);
            flagNotify.store(false);
            return 0;
        }

        return -1;
    }
};

template <>
class notifyCond<void>
{
private:

    std::atomic_bool    flagNotify;
    std::mutex          mutex_notify;
    std::condition_variable cond_var;

public:
    notifyCond():flagNotify(false){}
    ~notifyCond(){}

    void conditionPub(){
        std::unique_lock<std::mutex> ulock(mutex_notify);
        flagNotify.store(true);
        cond_var.notify_one();

    }


    int conditionWait(std::chrono::milliseconds time){
        std::unique_lock<std::mutex> ulock(mutex_notify);
        if(cond_var.wait_for(ulock,time,[&](){return flagNotify.load();})){
            flagNotify.store(false);
            return 0;
        }

        return -1;
    }
};

#endif
